﻿// ******************************************************************************************************
// <copyright file="GraphicSemivariogram.cs" company="Caroso.inc">
//     Copyright (c) Carlos Osorio All rights reserved.
// </copyright>
// ******************************************************************************************************
// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); 
// you may not use this file except in compliance with the License. You may obtain a copy of the License at 
// http:// www.mozilla.org/MPL/ 
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF 
// ANY KIND, either express or implied. See the License for the specificlanguage governing rights and 
// limitations under the License. 
// 
// The Original Code is this.mapWindow 
// 
// The Initial Developer of this version of the Original Code is Carlos Osorio
// 
// Contributor(s): (Open source contributors should list themselves and their modifications here). 
// Change Log: 
// Date           Changed By      Notes
// 22 Nov 2010    Carlos Osorio   Inital upload 
// ******************************************************************************************************
namespace Velsto
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// Generate the histogram
    /// </summary>
    public class GraphicHistogram
    {
        /// <summary>
        /// Width of the rectangle container for graph.
        /// </summary>
        private int widthGraph = 550; 
    
        /// <summary>
        /// Height of the rectangle container for graph.
        /// </summary>
        private int heightGraph = 200;   

        /// <summary>
        /// X-axis for the graph.
        /// </summary>
        private ArrayList graphXAxis;   

        /// <summary>
        /// Y-Axis for the graph.
        /// </summary>
        private ArrayList graphYAxis;
        
        /// <summary>
        /// Color for the graph.
        /// </summary>
        private ArrayList graphXYColor; 
        
        /// <summary>
        /// X-axis for the graph.
        /// </summary>
        private ArrayList graphx1Axis;   

        /// <summary>
        /// Y-Axis for the graph.
        /// </summary>
        private ArrayList graphy1Axis;  

        /// <summary>
        /// Color of the line graph.
        /// </summary>
        private Color graphColorL = Color.Red; 

        /// <summary>
        /// Slice for X Axis.
        /// </summary>
        private float graphXSlice = 1;            

        /// <summary>
        /// Slice for Y Axis.
        /// </summary>
        private float graphYSlice = 1;           

        /// <summary>
        /// Graphics Object.
        /// </summary>
        private Graphics objGraphics;        

        /// <summary>
        /// Bitmap that will contain the graph
        /// </summary>
        private Bitmap objBitmap;           

        /// <summary>
        /// Default Title for X-Axis.
        /// </summary>
        private string graphXAxisText = "Distances m";            

        /// <summary>
        /// Default Title for Y-Axis.
        /// </summary>
        private string graphYAxisText = "Semivariogram";           

        /// <summary>
        /// Default Graph Title.
        /// </summary>
        private string graphTitle = "Line Graph";          

        /// <summary>
        /// Default Graph Title Back Color.
        /// </summary>
        private Color graphTitleBackColor = Color.White;   

        /// <summary>
        /// Default Graph Title Fore Color.
        /// </summary>
        private Color graphTitleForeColor = Color.Black; 

        /// <summary>
        /// Initial value of graphic in Y
        /// </summary>
        private float graphYrealValue = 10;

        /// <summary>
        /// Initial value of graphic in X
        /// </summary>
        private float graphXrealValue = 10;

        /// <summary>
        /// Proportion X
        /// </summary>
        private float graphXprop = 1;

        /// <summary>
        /// Proportion Y
        /// </summary>
        private float graphYprop = 1;

        private float minD = 0.0f;

        /// <summary>
        /// Gets or sets of With of the Graphic
        /// </summary>
        public int Width
        {
            get 
            { 
                return this.widthGraph;
            }

            set
            {
                if (value > 20)
                {
                    this.widthGraph = value;
                }
            }
        }
        
        /// <summary>
        /// Gets or sets the Height for the rectangle container of graph.
        /// </summary>
        public int Height
        {
            get 
            { 
                return this.heightGraph; 
            }

            set
            {
                if (value > 20)
                {
                    this.heightGraph = value;
                }
            }
        }
        
        /// <summary>
        /// Gets or sets the X-Axis pixels for the graph.
        /// </summary>
        public ArrayList XAxis
        {
            get { return this.graphXAxis; }

            set { this.graphXAxis = value; }
        }

        /// <summary>
        /// Gets or sets the Y-Axis pixels for the graph.
        /// </summary>
        public ArrayList YAxis
        {
            get { return this.graphYAxis; }
            set { this.graphYAxis = value; }
        }
        
        /// <summary>
        /// Gets or sets the Y-Axis pixels for the graph.
        /// </summary>
        public ArrayList XYColor
        {
            get { return this.graphXYColor; }
            set { this.graphXYColor = value; }
        }
        
        /// <summary>
        /// Gets or sets the Color of the line Graph.
        /// </summary>
        public ArrayList X1Axis
        {
            get { return this.graphx1Axis; }
            set { this.graphx1Axis = value; }
        }

        /// <summary>
        /// Gets or sets the Y-Axis pixels for the graph.
        /// </summary>
        public ArrayList Y1Axis
        {
            get { return this.graphy1Axis; }
            set { this.graphy1Axis = value; }
        }

        /// <summary>
        /// Gets or sets the Color of the line Graph.
        /// </summary>
        public Color GraphColor
        {
            get { return this.graphColorL; }
            set { this.graphColorL = value; }
        }

        /// <summary>
        /// Gets or sets the X Axis Slice.
        /// </summary>
        public float XSlice
        {
            get { return this.graphXSlice; }
            set { this.graphXSlice = value; }
        }

        /// <summary>
        /// Gets or sets the Y Axis Slice.
        /// </summary>
        public float YSlice
        {
            get { return this.graphYSlice; }
            set { this.graphYSlice = value; }
        }

        /// <summary>
        /// Gets or sets the X-Axis Test.
        /// </summary>
        public string XAxisText
        {
            get { return this.graphXAxisText; }
            set { this.graphXAxisText = value; }
        }

        /// <summary>
        /// Gets or sets the Y-Axis Test.
        /// </summary>
        public string YAxisText
        {
            get { return this.graphYAxisText; }
            set { this.graphYAxisText = value; }
        }

        /// <summary>
        /// Gets or sets the title for the Graph.
        /// </summary>
        public string Title
        {
            get { return this.graphTitle; }
            set { this.graphTitle = value; }
        }

        /// <summary>
        /// Gets or sets the title Backcolor.
        /// </summary>
        public Color TitleBackColor
        {
            get { return this.graphTitleBackColor; }
            set { this.graphTitleBackColor = value; }
        }

        /// <summary>
        /// Gets or sets the Title ForeColor.
        /// </summary>
        public Color TitleForeColor
        {
            get 
            { 
                return this.graphTitleForeColor; 
            }

            set 
            { 
                this.graphTitleForeColor = value; 
            }
        }

        /// <summary>
        /// Gets or sets of real value in X
        /// </summary>
        public float XrealValue 
        {
            get 
            {
                return this.graphXrealValue; 
            }

            set 
            {
                this.graphXrealValue = value; 
            }
        }

        /// <summary>
        /// Gets or sets of real value in Y
        /// </summary>
        public float YrealValue 
        {
            get 
            { 
                return this.graphYrealValue; 
            }

            set 
            {
                this.graphYrealValue = value; 
            }
        }

        public float GraphXprop
        {
            get { return this.graphXprop; }
            set { this.graphXprop = value;}
        }
  
        public float GraphYprop
        {
            get { return this.graphYprop; }
            set { this.graphYprop = value; }
        }
  
        public float MinD
        {
            get
            {
                return this.minD;
            }

            set
            {
                this.minD = value;
            }
        }
        /// <summary>
        /// Draw line in the graph
        /// </summary>
        /// <param name="x1">Value of variable x1</param>
        /// <param name="y1">Value of variable y1</param>
        /// <param name="x2">Value of variable x2</param>
        /// <param name="y2">Value of variable y2</param>
        public void DrawLine(float x1, float y1, float x2, float y2) 
        {
            x1 = x1 + this.XSlice;
            x2 = x2 + this.XSlice;
            y1 = this.Height - this.YSlice - y1;
            y2 = this.Height - this.YSlice - y2;
            this.objGraphics.DrawLine(new Pen(new SolidBrush(Color.Black), 1), x1, y1, x2, y2);
        }
        /// <summary>
        /// Draw filled rectangle in the graph
        /// </summary>
        /// <param name="x1">Value of variable x1</param>
        /// <param name="y1">Value of variable y1</param>
        /// <param name="x2">Value of variable x2</param>
        /// <param name="y2">Value of variable y2</param>
        /// <param name="c1">Value of variable c1</param>
        public void FillRectangle(float x1, float y1, float x2, float y2, Color c1)
        {
            float w1, h1;
            float ystart;
            w1 = Math.Abs(x2 - x1);
            h1 = Math.Abs(y2 - y1);
            x1 = x1 + this.XSlice;
            ystart = this.Height - this.YSlice - y2;
            this.objGraphics.FillRectangle(new SolidBrush(c1), x1, ystart, w1, h1);
        }
        /// <summary>
        /// Draw Text in the graph
        /// </summary>
        /// <param name="x1">X position</param>
        /// <param name="y1">Y position</param>
        /// <param name="text">Text to be showed</param>
        /// <param name="size">Size of the font</param>
        public void DrawText(float x1, float y1, string text, int size)
        {
            x1 = x1 + this.XSlice;
            y1 = this.Height - this.YSlice - y1;
            this.objGraphics.DrawString(text, new Font("Verdana", size), new SolidBrush(Color.Black), x1, y1);
        }

        /// <summary>
        /// Draw point
        /// </summary>
        /// <param name="x1">X position</param>
        /// <param name="y1">Y position</param>
        /// <param name="size">Size of point</param>
        public void DrawPoint(float x1, float y1,  int size)
        {
            x1 = x1 + this.XSlice;
            y1 = this.Height - this.YSlice - y1;
            this.objGraphics.FillEllipse(new SolidBrush(Color.Red), x1, y1, size, size);
            this.objGraphics.DrawEllipse(new Pen(new SolidBrush(Color.Red)), x1, y1, size, size);
        }

        /// <summary>
        /// Initialize the graph
        /// </summary>
        public void InitializeGraph()
        {
            ////Creating a bitmap image with given height and width.
            this.objBitmap = new Bitmap(this.Width, this.Height);
            ////Getting the bitmap image into the graphics portion of the screen.
            this.objGraphics = Graphics.FromImage(this.objBitmap);
            ////Filling the rectangle portion of the graphics with custom color.
            this.objGraphics.FillRectangle(new SolidBrush(Color.White), 0, 0, this.Width, this.Height);
            this.DrawLine(0, 0, this.Width - (2 * this.XSlice), 0);
            this.DrawLine(0, 0, 0, this.Height - (2 * this.YSlice));
            this.SetAxisText(ref this.objGraphics);
            ////Sets the title for the Graph.
            this.CreateTitle(ref this.objGraphics);
        }

        /// <summary>
        /// Create graph
        /// </summary>
        /// <param name="graphColor">Color of the graph</param>
        public void CreateGraph(Color graphColor)
        {
            this.GraphColor = graphColor;
            this.SetPoints(ref this.objGraphics);
        }

        /// <summary>
        /// Define initial lines
        /// </summary>
        public void CreateLines() 
        {
            this.SetPixels(ref this.objGraphics);
        }

        /// <summary>
        /// Get the Bitmap container
        /// </summary>
        /// <returns>Object container</returns>
        public Bitmap GetGraph()
        {
            ////Creating X-Axis slices.
            //this.SetXAxis(ref this.objGraphics, this.Multip(this.XrealValue));
            //this.SetXAxis(ref this.objGraphics, this.XrealValue);
            ////Creating Y-Axis slices.
            this.SetYAxis(ref this.objGraphics, this.Multip(this.YrealValue));
            return this.objBitmap;
        }

        /// <summary>
        /// Create the sub items in each axis
        /// </summary>
        /// <param name="number">Number of items</param>
        /// <returns>length of the division</returns>
        public float Multip(float number) 
        {
            float aux = 0;
            if (number <= 1)
            {
                aux = number;
                int i = 1;
                int n = 0;
                while (number < 1) 
                {
                    i = i * 10;
                    n += 1;
                    number = aux * i;
                }

                aux = (float)Math.Round(aux, n);
                return aux;
            }
            else 
            {
                aux = number;
                int i = 1;
                int n = 0;
                while (number > 1)
                {
                    i = i * 10;
                    n += 1;
                    number = aux / i;
                }

                aux = aux / i;
                aux = (float)Math.Round(aux, 1);
                return aux * i;
            }
        }

        /// <summary>
        /// Draw the items in X
        /// </summary>
        /// <param name="objGraphics">Object container</param>
        /// <param name="islices">Number of Slices</param>
        private void SetXAxis(ref Graphics objGraphics, float islices)
        {
            float x1 = 0, y1 = 3, x2 = 0, y2 = -3;
            int icount = 0;
            float tickValue = 0.0f;
            int isliceCount = 1;

            for (int iindex = 0; iindex <= (this.Width - (2 * this.XSlice)); iindex += 10)
            {
                if (icount == 5)
                {
                    this.DrawLine(x1 + iindex, y1, x2 + iindex, y2);
                    tickValue = this.MinD + (islices * isliceCount);
                    //this.DrawText(x1 + iindex - 10, y2, Convert.ToString(this.MinD + (islices * isliceCount)), 6);
                    if (tickValue > 100.0 || tickValue < -100.0)
                    {
                        this.DrawText(x1 + iindex - 10, y2, tickValue.ToString("0.0"), 6);
                    }
                    else if (tickValue > 1.0 || tickValue < -1.0)
                    {
                        this.DrawText(x1 + iindex - 10, y2, tickValue.ToString("0.000"), 6);
                    }
                    else
                    {
                        this.DrawText(x1 + iindex - 10, y2, tickValue.ToString("e1"), 6);
                    }
                    icount = 0;
                    isliceCount++;
                }
                else
                {
                    this.DrawLine(x1 + iindex, y1 - 2, x2 + iindex, y2 + 2);
                }

                icount++;
            }
        }

        /// <summary>
        /// Draw the XAxis
        /// </summary>
        /// <param name="objGraphics">Object container</param>
        /// <param name="islices">Number of Slices</param>
        public void SetXAxis2(List<double> ListXAxisValues)
        {
            float x1 = 0, y1 = 3, x2 = 0, y2 = -3;
            float tickValue = 0.0f;

            for (int iindex = 0; iindex < ListXAxisValues.Count; iindex++)
            {
                x1 = (float.Parse(ListXAxisValues[iindex].ToString()) - this.MinD) * this.graphXprop;
                this.DrawLine(x1, y1, x1, y2);
                tickValue = float.Parse(ListXAxisValues[iindex].ToString());
                if (tickValue > 100.0 || tickValue < -100.0)
                {
                    this.DrawText(x1 - 10, y2, tickValue.ToString("0.0"), 6);
                }
                else if (tickValue > 1.0 || tickValue < -1.0)
                {
                    this.DrawText(x1 - 10, y2, tickValue.ToString("0.000"), 6);
                }
                else
                {
                    this.DrawText(x1 - 10, y2, tickValue.ToString("e1"), 6);
                }
            }
        }   
        /// <summary>
        /// Draw the items in Y
        /// </summary>
        /// <param name="objGraphics">Object container</param>
        /// <param name="islices">Number of Slices</param>
        private void SetYAxis(ref Graphics objGraphics, float islices)
        {
            int x1 = 3;
            int y1 = 0;
            int x2 = -3;
            int y2 = 0;
            int icount = 0;
            int isliceCount = 1;

            for (int iindex = 0; iindex < this.Height - (2 * this.YSlice); iindex += 10)
            {
                if (icount == 5)
                {
                    this.DrawLine(x1, y1 + iindex, x2, y2 + iindex);
                    this.DrawText(x1 - 18, y2 + iindex + 6, Convert.ToString(islices * isliceCount), 6);
                    icount = 0;
                    isliceCount++;
                }
                else
                {
                    this.DrawLine(x1 - 2, y1 + iindex, x2 + 2, y2 + iindex);
                }

                icount++;
            }
        }

        /// <summary>
        /// Draw the points without reference
        /// </summary>
        /// <param name="objGraphics">Object container</param>
        private void SetPixels(ref Graphics objGraphics)
        {
            //this.graphXprop = 50 / this.Multip(this.XrealValue);
            this.graphXprop = 50 / this.XrealValue;
            this.graphYprop = 50 / this.Multip(this.YrealValue);
            float x1 = (float.Parse(this.graphx1Axis[0].ToString()) - this.MinD) * this.graphXprop;
            float y1 = float.Parse(this.graphy1Axis[0].ToString()) * this.graphYprop;

            if (this.graphx1Axis.Count == this.graphy1Axis.Count)
            {
                for (int ixaxis = 0, iyaxis = 0; ixaxis < this.graphx1Axis.Count - 1
                           && iyaxis < this.graphy1Axis.Count - 1; ixaxis++, iyaxis++)
                {
                    if (x1 > 0.0f && x1 < (this.Width - (2 * this.XSlice)))
                    {
                        //this.DrawLine(
                        this.FillRectangle(
                            x1,
                            //y1,
                            0.0f,
                             (float.Parse(this.graphx1Axis[ixaxis + 1].ToString()) - this.MinD) * this.graphXprop,
                             //float.Parse(this.graphy1Axis[iyaxis + 1].ToString()) * this.graphYprop,
                             float.Parse(this.graphy1Axis[iyaxis].ToString()) * this.graphYprop,
                             (Color) graphXYColor[ixaxis]);
                    }
                    x1 = (float.Parse(this.graphx1Axis[ixaxis + 1].ToString()) - this.MinD) * this.graphXprop;
                    y1 = float.Parse(this.graphy1Axis[iyaxis + 1].ToString()) * this.graphYprop;
                }
            }
        }
        
        /// <summary>
        /// Draw points taking into account the reference
        /// </summary>
        /// <param name="objGraphics">Object container</param>
        private void SetPoints(ref Graphics objGraphics)
        {
            this.graphXprop = 50 / this.Multip(this.XrealValue);
            this.graphYprop = 50 / this.Multip(this.YrealValue);
            float x1 = float.Parse(this.XAxis[0].ToString()) * this.graphXprop;
            float y1 = float.Parse(this.YAxis[0].ToString()) * this.graphYprop;

            if (this.XAxis.Count == this.YAxis.Count)
            {
                for (int i = 0; i < this.XAxis.Count; i++)
                {
                    this.DrawPoint((float.Parse(this.XAxis[i].ToString()) - 1.5f) * this.graphXprop, (float.Parse(this.YAxis[i].ToString()) + 1.5f) * this.graphYprop, 3);
                }
            }
        }

        /// <summary>
        /// Draw text of all items
        /// </summary>
        /// <param name="objGraphics">Object container</param>
        private void SetAxisText(ref Graphics objGraphics)
        {
            objGraphics.DrawString(
                this.XAxisText, 
                new Font("Verdana", 7),
                new SolidBrush(Color.Black),
                (this.Width / 2) - this.XSlice,
                this.Height - this.YSlice + 20);

            int x = (int) 2;
            int y = (int)((this.Height / 2) - this.YSlice);
            for (int iindex = 0; iindex < this.YAxisText.Length; iindex++)
            {
                objGraphics.DrawString(
                    this.YAxisText[iindex].ToString(),
                    new Font("Verdana", 7),
                    new SolidBrush(Color.Black),
                    x,
                    y);
                y += 8;
            }
        }

        /// <summary>
        /// Draw the title of the graph
        /// </summary>
        /// <param name="objGraphics">Object container</param>
        private void CreateTitle(ref Graphics objGraphics)
        {
            objGraphics.FillRectangle(
                new SolidBrush(this.TitleBackColor),
                       (this.Width / 2) - this.XSlice,
                       10,
                       this.Width - (2 * this.XSlice),
                       this.YSlice);
            Rectangle rect = new Rectangle((int)((this.Width / 2) - this.XSlice), (int)0, (int)(this.Width - (2 * this.XSlice)), (int)20);
            objGraphics.DrawString(
                this.Title,
                new Font("Verdana", 8),
                       new SolidBrush(this.TitleForeColor),
                       rect);
        }
    }
}
